<template>
  <t-upload
    v-model="files"
    :draggable="type === 'draggable'"
    :theme="type === 'image' ? 'image' : 'file'"
    :action="uploadPath"
    :max="limit"
    :multiple="limit !== 1"
    :headers="uploadHeaders"
    :tips="showTip && !files.length ? tip : ''"
    :abridge-name="[6, 6]"
    :size-limit="{ size: fileSize, unit: 'MB' }"
    :format-response="formatResponse"
    allow-upload-duplicate-file
    :before-upload="beforeUpload"
    @success="onSuccess"
    @fail="handleFail"
  />
</template>

<script setup lang="ts">
import { MessagePlugin, SuccessContext, UploadFailContext, UploadFile } from 'tdesign-vue-next';
import { computed, PropType, ref, watch } from 'vue';

import { uploadUrl } from '@/api/upload';
import { t } from '@/locales';
import { useUserStore } from '@/store';
import { FileItem } from '@/types/interface';

const user = useUserStore();
const files = ref<UploadFile[]>([]);
const emit = defineEmits(['update:value']);

const props = defineProps({
  uploadPath: {
    type: String,
    default: uploadUrl,
  },
  headers: {
    type: Object as PropType<Record<string, string>>,
    default: () => ({}),
  },
  type: {
    type: String as PropType<'draggable' | 'image' | 'button'>,
    default: 'image',
  },
  valueType: {
    type: String as PropType<'json' | 'string' | 'data'>,
    default: 'string',
  },
  value: {
    type: [String, Array] as PropType<string | FileItem[]>,
    default: '',
  },
  limit: {
    type: Number,
    default: 5,
  },
  fileSize: {
    type: Number,
    default: 5,
  },
  fileType: {
    type: Array as PropType<string[]>,
    default: () => ['png', 'jpg', 'jpeg'],
  },
  showTip: {
    type: Boolean,
    default: true,
  },
  tip: {
    type: String,
    default: () => t('components.upload.tips'),
  },
});

const uploadHeaders = computed(() => ({
  [user.tokenHead]: user.token,
  ...props.headers,
}));

watch(
  () => props.value,
  (val) => {
    if (!val) {
      files.value = [];
      return;
    }

    try {
      if (props.valueType === 'json') {
        files.value = val as UploadFile[];
      } else if (props.valueType === 'string') {
        // 处理字符串类型的值（JSON 字符串）
        const parsedValue = typeof val === 'string' ? JSON.parse(val) : val;
        const parsedFiles = (parsedValue as FileItem[]).filter((item) => item.data);
        files.value = parsedFiles.map((item) => ({
          ...item,
          url: item.data,
          // 保持与 UploadFile 类型兼容
          name: item.name || item.data.split('/').pop() || 'file',
        }));
      } else {
        // 处理逗号分隔的字符串值
        const valTmp = val as string;
        const fileList = valTmp.split(',').filter(Boolean);
        files.value = fileList.map((item) => ({
          name: item.split('/').pop() || 'file',
          url: item,
          data: item,
        }));
      }
    } catch (error) {
      console.error('文件解析失败:', error, { value: val });
      files.value = [];
    }
  },
  { immediate: true, deep: true },
);

const handleFail = (_: UploadFailContext) => {
  MessagePlugin.error(t('components.upload.error'));
};

const beforeUpload = (file: UploadFile): boolean => {
  const fileExtension = file.name.split('.').pop()?.toLowerCase() || '';

  const isValidType = props.fileType.some((type) => {
    const typeToCheck = type.toLowerCase();
    return file.type.toLowerCase().includes(typeToCheck) || fileExtension === typeToCheck;
  });

  if (!isValidType) {
    MessagePlugin.error(`${t('components.upload.fileType')}: ${props.fileType.join('、')}!`);
    return false;
  }

  const isValidSize = file.size / 1024 / 1024 < props.fileSize;
  if (!isValidSize) {
    MessagePlugin.error(`${t('components.upload.fileSize')} ${props.fileSize} MB!`);
    return false;
  }

  return true;
};

const onSuccess = (context: SuccessContext) => {
  let result: string | FileItem[];

  const formatFileItem = (file: UploadFile): FileItem => {
    return {
      name: file.name,
      data: file.response?.data || file.data,
    };
  };

  if (props.valueType === 'json') {
    result = context.fileList.map(formatFileItem);
  } else if (props.valueType === 'string') {
    result = JSON.stringify(context.fileList.map(formatFileItem));
  } else {
    result = context.fileList
      .map((file) => file.response?.data || '')
      .filter(Boolean)
      .join(',');
  }
  emit('update:value', result);
};

const formatResponse = (res: any) => {
  if (res.code !== 200) {
    return { ...res, error: res.message };
  }
  const fileData = res.data;
  return {
    ...res,
    name: fileData.name,
    data: fileData.url,
  };
};
</script>
